package cn.huaqingcheng.tool.http;

import cn.huaqingcheng.tool.core.StrTool;
import cn.huaqingcheng.tool.core.StringPool;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
import java.util.Map;
import java.util.function.Function;

/**
 * HTTP 请求
 **/
@SuppressWarnings({"unused", "ClassNamePrefixedWithPackageName"})
@Getter
@EqualsAndHashCode
@NoArgsConstructor
@Accessors(fluent = true, chain = true)
public class HttpRequest {

    /**
     * query 参数
     */
    @NotNull
    private final HttpQuerys query = new HttpQuerys();

    /**
     * 请求头
     */
    @NotNull
    private final HttpHeaders header = new HttpHeaders();

    /**
     * URL
     * 不含 query 的 {@link java.net.URL}
     */
    @Nullable
    private URL url;

    /**
     * 请求方法
     */
    @NotNull
    @Setter
    private HttpMethod method = HttpMethod.GET;

    @NotNull
    @Setter
    private HttpVersion version = HttpVersion.HTTP_1_1;

    /**
     * 请求体
     */
    @Nullable
    @Setter
    private Object body;

    /**
     * 超时 默认一分钟
     */
    @Setter
    private Duration timeout = Duration.ofSeconds(60);

    /**
     * @see #method(HttpMethod)
     */
    public HttpRequest GET() {
        method = HttpMethod.GET;
        return this;
    }

    /**
     * @see #method(HttpMethod)
     */
    public HttpRequest HEAD() {
        method = HttpMethod.HEAD;
        return this;
    }

    /**
     * @see #method(HttpMethod)
     */
    public HttpRequest PUT() {
        method = HttpMethod.PUT;
        return this;
    }

    /**
     * @see #method(HttpMethod)
     */
    public HttpRequest POST() {
        method = HttpMethod.POST;
        return this;
    }

    /**
     * @see #method(HttpMethod)
     */
    public HttpRequest DELETE() {
        method = HttpMethod.DELETE;
        return this;
    }

    @Nullable
    public String urlProtocol() {
        return urlGet(URL::getProtocol);
    }

    @Nullable
    private <T> T urlGet(@NotNull Function<URL, T> fun) {
        if (url != null) {
            return fun.apply(url);
        }
        return null;
    }

    @Nullable
    public String urlUserInfo() {
        return urlGet(URL::getUserInfo);
    }

    @Nullable
    public Integer urlPort() {
        return urlGet(URL::getPort);
    }

    @Nullable
    public String urlHost() {
        return urlGet(URL::getHost);
    }

    @Nullable
    public String urlPath() {
        return urlGet(URL::getPath);
    }

    @Nullable
    public String urlRef() {
        return urlGet(URL::getRef);
    }

    public HttpRequest url(URL url) {
        String queryStr = url.getQuery();
        if (StrTool.isNotEmpty(queryStr)) {
            query.putAll(queryStr);
            // 确保 this.url 不包含 query 部分
            return url(url.toString().replaceFirst("\\?" + queryStr, StringPool.EMPTY));
        }
        this.url = url;

        return this;
    }

    public HttpRequest url(String url) {
        try {
            return url(new URL(url));
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    public HttpRequest query(Map<String, String> query) {
        this.query.addAll(query);
        return this;
    }

    public HttpRequest query(String queryStr) {
        query.addAll(queryStr);
        return this;
    }

    public HttpRequest query(String key, Object value) {
        query.add(key, value);
        return this;
    }

    public HttpRequest header(HttpHeader name, String value) {
        header.add(name, value);
        return this;
    }

    public HttpRequest header(String name, String value) {
        header.add(name, value);
        return this;
    }

    public HttpRequest header(Map<String, String> header) {
        this.header.addAll(header);
        return this;
    }

    @Override
    public String toString() {
        return toString(true, true);
    }

    public String toString(boolean showHeader, boolean showBody) {
        StringBuilder sb = new StringBuilder();

        sb.append(method).append(StringPool.SPACE)
            .append(url()).append(StringPool.SPACE)
            .append(version);

        if (header.isNotEmpty() && showHeader) {
            sb.append(StringPool.LINE_BREAK)
                .append(header);
        }
        if (body != null && showBody) {
            sb.append(StringPool.LINE_BREAK)
                .append(body);
        }

        return sb.toString();
    }

    /**
     * 含 query 的完整 URL
     */
    @NotNull
    public String url() {
        if (query.isEmpty()) {
            return url != null ? url.toString() : StringPool.EMPTY;
        }
        if (url == null) {
            return StringPool.EMPTY;
        }
        String ref = url.getRef();
        return StrTool.isEmpty(ref)
               ? url + StringPool.ASK + query
               : StrTool.removeSuffix(url.toString(), StringPool.JING + ref) + StringPool.ASK + query + StringPool.JING + ref;
    }

}
